//// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
//package com.linqingying.gitcode.pullrequest.ui.details.model.impl
//
//import com.intellij.collaboration.async.modelFlow
//import com.intellij.collaboration.messages.CollaborationToolsBundle
//import com.intellij.collaboration.ui.codereview.action.ReviewMergeCommitMessageDialog
//import com.intellij.collaboration.ui.codereview.commits.splitCommitMessage
//import com.intellij.collaboration.ui.codereview.details.data.ReviewRole
//import com.intellij.collaboration.ui.codereview.details.data.ReviewState
//import com.intellij.collaboration.util.CollectionDelta
//import com.intellij.collaboration.util.ComputedResult
//import com.intellij.collaboration.util.SingleCoroutineLauncher
//import com.intellij.openapi.diagnostic.Logger
//import com.intellij.openapi.diagnostic.logger
//import com.intellij.openapi.progress.EmptyProgressIndicator
//import com.intellij.openapi.project.Project
//import com.intellij.openapi.util.text.StringUtil
//import com.intellij.platform.util.coroutines.childScope
//import com.intellij.util.io.await
//import kotlinx.coroutines.CoroutineScope
//import kotlinx.coroutines.flow.*
//import com.linqingying.gitcode.api.data.GCRepositoryPermissionLevel
//import com.linqingying.gitcode.api.data.GCUser
//import com.linqingying.gitcode.api.data.pullrequest.*
//import com.linqingying.gitcode.i18n.GitCodeBundle
//import com.linqingying.gitcode.pullrequest.data.GCPRMergeabilityState
//import com.linqingying.gitcode.pullrequest.data.GCPullRequestPendingReview
//import com.linqingying.gitcode.pullrequest.data.provider.GCPRChangesDataProvider
//import com.linqingying.gitcode.pullrequest.data.provider.GCPRDetailsDataProvider
//import com.linqingying.gitcode.pullrequest.data.provider.GCPRStateDataProvider
//import com.linqingying.gitcode.pullrequest.data.service.GCPRRepositoryDataService
//import com.linqingying.gitcode.pullrequest.data.service.GCPRSecurityService
//import com.linqingying.gitcode.pullrequest.ui.GCReviewersUtils
//import com.linqingying.gitcode.pullrequest.ui.details.model.GCPRReviewFlowViewModel
//import com.linqingying.gitcode.pullrequest.ui.details.model.RepositoryRestrictions
//import com.linqingying.gitcode.pullrequest.ui.review.GCPRReviewViewModelHelper
//import com.linqingying.gitcode.pullrequest.ui.review.GCPRSubmitReviewViewModel
//import com.linqingying.gitcode.ui.avatars.GCAvatarIconsProvider
//import com.linqingying.gitcode.ui.util.GCUIUtil
//import java.util.concurrent.CompletableFuture
//import javax.swing.JComponent
//import kotlin.coroutines.cancellation.CancellationException
//
//private val LOG: Logger = logger<GCPRReviewFlowViewModel>()
//
//class GCPRReviewFlowViewModelImpl internal constructor(
//  parentCs: CoroutineScope,
//  private val project: Project,
//  private val detailsState: StateFlow<GCPullRequest>,
//  private val repositoryDataService: GCPRRepositoryDataService,
//  private val securityService: GCPRSecurityService,
//  private val avatarIconsProvider: GCAvatarIconsProvider,
//  private val dataProvider: GCPRDetailsDataProvider,
//  private val stateData: GCPRStateDataProvider,
//  private val changesData: GCPRChangesDataProvider,
//  private val reviewVmHelper: GCPRReviewViewModelHelper
//) : GCPRReviewFlowViewModel {
//  private val cs = parentCs.childScope()
//
//  private val taskLauncher = SingleCoroutineLauncher(cs)
//
//  private val currentUser = securityService.currentUser
//  private val ghostUser = securityService.ghostUser
//
//  override val isBusy: Flow<Boolean> = taskLauncher.busy
//
//  // TODO: handle error
//  private val mergeabilityState: StateFlow<GCPRMergeabilityState?> = stateData.mergeabilityState
//    .map { it.getOrNull() }
//    .stateIn(cs, SharingStarted.Eagerly, null)
//
//  override val requestedReviewers: SharedFlow<List<GCPullRequestRequestedReviewer>> =
//    detailsState.map { it.reviewRequests.mapNotNull(GCPullRequestReviewRequest::requestedReviewer) }
//      .shareIn(cs, SharingStarted.Lazily, 1)
//
//  override val reviewerReviews: SharedFlow<Map<GCPullRequestRequestedReviewer, ReviewState>> = detailsState.map { details ->
//    val author = details.author
//    val reviews = details.reviews
//    val reviewers = details.reviewRequests.mapNotNull(GCPullRequestReviewRequest::requestedReviewer)
//    GCReviewersUtils.getReviewsByReviewers(author, reviews, reviewers, ghostUser)
//  }.shareIn(cs, SharingStarted.Lazily, 1)
//
//  private val isApproved: SharedFlow<Boolean> = combine(reviewerReviews, mergeabilityState) { reviews, state ->
//    val requiredApprovingReviewsCount = state?.requiredApprovingReviewsCount ?: 0
//    val approvedReviews = reviews.count { it.value == ReviewState.ACCEPTED }
//    return@combine if (requiredApprovingReviewsCount == 0) approvedReviews > 0 else approvedReviews >= requiredApprovingReviewsCount
//  }.modelFlow(cs, LOG)
//
//  override val reviewState: SharedFlow<ReviewState> = combine(detailsState, isApproved) { detailsState, isApproved ->
//    if (isApproved) return@combine ReviewState.ACCEPTED
//    return@combine when (detailsState.reviewDecision) {
//      GCPullRequestReviewDecision.APPROVED -> ReviewState.ACCEPTED
//      GCPullRequestReviewDecision.CHANGES_REQUESTED -> ReviewState.WAIT_FOR_UPDATES
//      GCPullRequestReviewDecision.REVIEW_REQUIRED -> ReviewState.NEED_REVIEW
//      null -> ReviewState.NEED_REVIEW
//    }
//  }.modelFlow(cs, LOG)
//
//  override val role: SharedFlow<ReviewRole> = detailsState.map { details ->
//    when {
//      details.isAuthor(currentUser) -> ReviewRole.AUTHOR
//      details.isReviewer(currentUser) -> ReviewRole.REVIEWER
//      else -> ReviewRole.GUEST
//    }
//  }.shareIn(cs, SharingStarted.Lazily, 1)
//
//  override val pendingReview: StateFlow<ComputedResult<GCPullRequestPendingReview?>> = reviewVmHelper.pendingReviewState
//  override val pendingComments: Flow<Int> = pendingReview.map { it.result?.getOrNull()?.commentsCount ?: 0 }
//
//  override val repositoryRestrictions = RepositoryRestrictions(securityService)
//
//  override val userCanManageReview: Boolean = securityService.currentUserHasPermissionLevel(GCRepositoryPermissionLevel.TRIAGE) ||
//                                              detailsState.value.viewerDidAuthor
//
//  override val userCanMergeReview: Boolean = securityService.currentUserHasPermissionLevel(GCRepositoryPermissionLevel.WRITE) &&
//                                             !securityService.isMergeForbiddenForProject()
//
//  override val isMergeEnabled: Flow<Boolean> = mergeabilityState.map {
//    it?.isRestricted == false && repositoryRestrictions.isMergeAllowed &&
//    it.canBeMerged && userCanMergeReview
//  }
//
//  override val isSquashMergeEnabled: Flow<Boolean> = mergeabilityState.map {
//    it?.isRestricted == false && repositoryRestrictions.isSquashMergeAllowed &&
//    it.canBeMerged && userCanMergeReview
//  }
//
//  override val isRebaseEnabled: Flow<Boolean> = mergeabilityState.map {
//    it?.isRestricted == false && repositoryRestrictions.isRebaseAllowed &&
//    it.canBeRebased && userCanMergeReview
//  }
//
//  override var submitReviewInputHandler: (suspend (GCPRSubmitReviewViewModel) -> Unit)? = null
//
//  override fun submitReview() {
//    val handler = submitReviewInputHandler
//    checkNotNull(handler) { "UI handler was not set" }
//    reviewVmHelper.submitReview(handler)
//  }
//
//  override fun mergeReview() = runAction {
//    val details = detailsState.value
//    val mergeability = mergeabilityState.value ?: return@runAction
//    val dialog = ReviewMergeCommitMessageDialog(project,
//                                                CollaborationToolsBundle.message("dialog.review.merge.commit.title"),
//                                                GitCodeBundle.message("pull.request.merge.pull.request", details.number),
//                                                details.title)
//    if (!dialog.showAndGet()) {
//      return@runAction
//    }
//    stateData.merge(EmptyProgressIndicator(), splitCommitMessage(dialog.message), mergeability.headRefOid).await()
//  }
//
//  override fun rebaseReview() = runAction {
//    val mergeability = mergeabilityState.value ?: return@runAction
//    stateData.rebaseMerge(EmptyProgressIndicator(), mergeability.headRefOid).await()
//  }
//
//  override fun squashAndMergeReview() = runAction {
//    val details = detailsState.value
//    val mergeability = mergeabilityState.value ?: return@runAction
//    val commits = changesData.loadCommitsFromApi().await()
//    val body = "* " + StringUtil.join(commits, { it.messageHeadline }, "\n\n* ")
//    val dialog = ReviewMergeCommitMessageDialog(project,
//                                                CollaborationToolsBundle.message("dialog.review.merge.commit.title.with.squash"),
//                                                GitCodeBundle.message("pull.request.merge.pull.request", details.number),
//                                                body)
//    if (!dialog.showAndGet()) {
//      return@runAction
//    }
//    val message = dialog.message
//    stateData.squashMerge(EmptyProgressIndicator(), splitCommitMessage(message), mergeability.headRefOid).await()
//  }
//
//  override fun closeReview() = runAction {
//    stateData.close(EmptyProgressIndicator()).await()
//  }
//
//  override fun reopenReview() = runAction {
//    stateData.reopen(EmptyProgressIndicator()).await()
//  }
//
//  override fun postDraftedReview() = runAction {
//    stateData.markReadyForReview(EmptyProgressIndicator()).await()
//  }
//
//  override fun removeReviewer(reviewer: GCPullRequestRequestedReviewer) = runAction {
//    val reviewers = requestedReviewers.first()
//    val delta = CollectionDelta(reviewers, reviewers - reviewer)
//    dataProvider.adjustReviewers(EmptyProgressIndicator(), delta).await()
//  }
//
//  override fun requestReview(parentComponent: JComponent) = runAction {
//    val reviewers = requestedReviewers.combine(reviewerReviews) { reviewers, reviews ->
//      reviewers + reviews.keys
//    }.first()
//    val selectedReviewers = GCUIUtil.showChooserPopup(
//      parentComponent,
//      GCUIUtil.SelectionPresenters.PRReviewers(avatarIconsProvider),
//      reviewers,
//      loadPotentialReviewers()
//    ).await()
//    dataProvider.adjustReviewers(EmptyProgressIndicator(), selectedReviewers).await()
//  }
//
//  private fun loadPotentialReviewers(): CompletableFuture<List<GCPullRequestRequestedReviewer>> {
//    val author = detailsState.value.author
//    return repositoryDataService.potentialReviewers.thenApply { reviewers ->
//      reviewers.mapNotNull { if (it == author) null else it }
//    }
//  }
//
//  override fun reRequestReview() = runAction {
//    val delta = requestedReviewers.combine(reviewerReviews) { reviewers, reviews ->
//      CollectionDelta(reviewers, reviewers + reviews.keys)
//    }.first()
//    dataProvider.adjustReviewers(EmptyProgressIndicator(), delta).await()
//  }
//
//  override fun setMyselfAsReviewer() = runAction {
//    val reviewers = requestedReviewers.first()
//    val delta = CollectionDelta(reviewers, reviewers + securityService.currentUser)
//    dataProvider.adjustReviewers(EmptyProgressIndicator(), delta).await()
//  }
//
//  private fun runAction(action: suspend () -> Unit) {
//    taskLauncher.launch {
//      try {
//        action()
//      }
//      catch (e: Exception) {
//        if (e is CancellationException) throw e
//        //TODO: handle???
//      }
//    }
//  }
//}
//
//private fun GCPullRequest.isAuthor(user: GCUser): Boolean =
//  author?.id == user.id
//
//private fun GCPullRequest.isReviewer(user: GCUser): Boolean =
//  reviewRequests.any { it.requestedReviewer?.id == user.id }
//  ||
//  reviews.any { it.author?.id == user.id }
